package com.donaldy.jvm.engine;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

import com.donaldy.jvm.cmd.ByteCodeCommand;
import com.donaldy.jvm.cmd.InvokeVirtualCmd;
import com.donaldy.jvm.method.Method;

public class StackFrame {

	private List<JavaObject> localVariableTable = new ArrayList<JavaObject>();
	private Stack<JavaObject> oprandStack = new Stack<JavaObject>();

	int index = 0;

	private Method m = null;

	private StackFrame callerFrame = null;

	public StackFrame getCallerFrame() {
		return callerFrame;
	}

	public void setCallerFrame(StackFrame callerFrame) {
		this.callerFrame = callerFrame;
	}




	public static  StackFrame create(Method m){

		StackFrame frame = new StackFrame( m );

		return frame;
	}


	private StackFrame(Method m) {
		this.m = m;

	}



	public JavaObject getLocalVariableValue(int index){
		return this.localVariableTable.get(index);
	}

	public Stack<JavaObject> getOprandStack(){
		return this.oprandStack;
	}

	public int getNextCommandIndex(int offset){

		ByteCodeCommand [] cmds = m.getCodeAttr().getCmds();
		for(int i=0;i<cmds.length; i++){
			if(cmds[i].getOffset() == offset){
				return i;
			}
		}
		throw new RuntimeException("Can't find next command");
	}

	public ExecutionResult execute(){

		ByteCodeCommand [] cmds = this.m.getCmds();

		while (this.index < cmds.length) {

			ExecutionResult result = new ExecutionResult();

			//缺省值是执行吓一条命令
			result.setNextAction(ExecutionResult.RUN_NEXT_CMD);

			System.out.println(cmds[this.index].toString());

			cmds[this.index].execute(this, result);

			if (result.isRunNextCmd()) {
				this.index ++;
			}
			else if (result.isExitCurrentFrame()) {
				return result;
			}
			else if (result.isPauseAndRunNewFrame()) {
				this.index ++;

				return result;
			}
			else if (result.isJump()) {
				int offset = result.getNextCmdOffset();
				this.index = getNextCommandIndex(offset);
			} else {
				index ++;
			}
		}

		//当前StackFrmae的指令全部执行完毕，可以退出了
		ExecutionResult result = new ExecutionResult();

		result.setNextAction(ExecutionResult.EXIT_CURRENT_FRAME);

		return result;

	}




	public void setLocalVariableTable(List<JavaObject> values){
		this.localVariableTable = values;
	}

	public void setLocalVariableValue(int index, JavaObject jo){
		//问题： 为什么要这么做？？
		if(this.localVariableTable.size()-1 < index){
			for(int i=this.localVariableTable.size(); i<=index; i++){
				this.localVariableTable.add(null);
			}
		}
		this.localVariableTable.set(index, jo);


	}

	public Method getMethod(){
		return m;
	}


}
